/*
----------------------------------------------------------------------------------------------------
This source file is part of the Gamut Framework
Copyright (c) 2007 by Ryan Holcombe

This program is free software; you can redistribute it and/or modify it under the terms of the GNU
Lesser General Public License as published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
----------------------------------------------------------------------------------------------------
*/


#ifndef _ManagerFactory_h_
#define _ManagerFactory_h_

#include <list>
#include <map>
#include <boost/shared_ptr.hpp>
#include "Singleton.h"


namespace Gamut
{
	class IManager;
	
	typedef boost::shared_ptr<IManager> IManagerPtr;
	typedef std::map<const std::string, IManagerPtr> RegisteredMap;
	typedef std::list<std::string> ActiveList;
	
	
	/**
 		All components must be registered with this factory
	*/

	class ManagerFactory : public Singleton<ManagerFactory>
	{
		private:
			//!< Managers that have been registered, but not necessary created
			RegisteredMap mRegisteredMap;

			//!< Managers that have been added, they will be updated each frame
			ActiveList mActiveList;

		public:
			
			/** Default Constructor
				\remarks
					All managers are registered here.\n
					If inherited, all new managers should be included in registerCustomerManagers().\n
					There can only be 1 instance from each type of manager created
			*/
			ManagerFactory();
			
			/**
				\brief destroy all managers
			*/
			~ManagerFactory();

			/**
				\brief additional managers are registered here
			*/
			virtual void registerCustomManagers() { }
			
			/**
				\brief registers a manager with the factory
				\param[in] manager pointer to the new manager
			*/
			IManagerPtr registerManager(IManagerPtr manager);
		
		
			/**
				\brief unregisters a component from the factory,
			 		   once unregistered no managers of this type can be created
				\param[in] name must be the same as what was used in registerManager()
				\remarks
					If there is a manager of this type already created, it will be destroyed
			*/
			void unregisterManager(const std::string& name);
		
		
			/**
				\brief adds a registered manager to the active list
				\param[in] name must be the same as what was used in registerManager()
				\return a pointer to the component object or NULL on a failure
			*/
			IManagerPtr addManager(const std::string& name);


			/**
				\brief removes a manager
				\param[in] name which manager to destroy
				\remarks
					Manager will no longer update each frame but will remain in the
					registered map in it's current state.
			*/
			void removeManager(const std::string& name);


			/*
				\brief returns a pointer to a registered manager
				\param[in] name which manager to get
			*/
			IManagerPtr getManager(const std::string& name) const;


			/*
				\brief returns whether or not a manager is active
				\param[in] 1 if the manager is in the active list, 0 otherwise
			*/
			bool isManagerActive(const std::string& name) const;


			/**
				\brief goes through each manager in the map and calls it's tick() function
			*/
			void tick(double elapsed);
	};
}


#endif
